// keel_clazz.cpp : Defines the exported functions for the DLL application.
//

#include "stdafx.h"

#include <time.h>

#include "backstage_tool_classcoder_ClassCoder.h"
#include "backstage_util_CodedClassLoader.h"
//jclass g_CodedClassLoader;
//jmethodID g_CodedClassLoader_defineClass;

#if 0
#include <Psapi.h>

HMODULE GetJavaDLLHMOD()
{
	HMODULE modList[1024/sizeof(HMODULE)];
	int n=0;
	EnumProcessModules(GetCurrentProcess(),modList,sizeof(modList),&n);

	TCHAR modName[MAX_PATH];
	for(int i=0;i<n;++i)
	{
		GetModuleFileName(modList[i],modName,_countof(modName));
		TCHAR *p=PathFindFileName(modName);
		if(p && _tcsicmp(p,_T("java.dll"))==0)
		{
			return modList[i];
		}
	}
	
	return NULL;
}
#endif
//////////////////////////////////////////////////////////////////////////
void sgenrand(DWORD s, DWORD *mt, int &mti)
{
	int x = s;
	for(int i=0;i<624;++i)
	{
		mt[i] = x & 0xFFFF0000;
		x = 69069 * x + 1;
		mt[i] |= (x & 0xFFFF0000) >> 16;
		x = 69069 * x + 1;
	}

	mti = 624;
}
DWORD genrand(DWORD *mt, int &mti)
{
	DWORD y;
	static DWORD mag01[]={0, 0x9908B0DF};

	if ( mti >= 624 )
	{
		if ( mti == 625 )
			sgenrand(4357, mt, mti);
		int kk;
		for (kk=0;kk<227;++kk) {
			y = (mt[kk]&0x80000000)|(mt[kk+1]&0x7FFFFFFF);
			mt[kk] = mt[kk+397] ^ (y >> 1) ^ mag01[y & 1];
		}
		for (;kk<623;++kk) {
			y = (mt[kk]&0x80000000)|(mt[kk+1]&0x7FFFFFFF);
			mt[kk] = mt[kk-227] ^ (y >> 1) ^ mag01[y & 1];
		}
		y = (mt[623]&0x80000000)|(mt[0]&0x7FFFFFFF);
		mt[623] = mt[396] ^ (y >> 1) ^ mag01[y & 0x1];

		mti = 0;
	}
	y = mt[mti++];

	y ^= (y >> 11);
	y ^= (y << 7) & 0x9D2C5680;
	y ^= (y << 15) & 0xEFC60000;
	y ^= (y >> 18);

	return y;
}
//////////////////////////////////////////////////////////////////////////
#define LEDWORD(x) \
(DWORD)(((((DWORD)(x)[0])<<24)&0xFF000000) || \
        ((((DWORD)(x)[1])<<16)&0x00FF0000) || \
        ((((DWORD)(x)[2])<< 8)&0x0000FF00) || \
        (( (DWORD)(x)[3])     &0x000000FF))

int g_mti=625;
DWORD g_mt[624];

JNIEXPORT jclass JNICALL Java_backstage_util_CodedClassLoader_defineClassNative( JNIEnv *env, jobject pthis, jstring s, jbyteArray abyte0, jobject)
{
// 	if(g_CodedClassLoader==NULL)
// 	{
// 		g_CodedClassLoader=env->NewGlobalRef(env->GetObjectClass(pthis));
// 	}
// 
// 	if(g_CodedClassLoader_defineClass==NULL)
// 	{
// 		g_CodedClassLoader_defineClass=env->GetMethodID(g_CodedClassLoader,"defineClass","(Ljava/lang/String;[BII)Ljava/lang/Class;");
// 	}

	jbyte *buf=reinterpret_cast<jbyte*>(env->GetPrimitiveArrayCritical(abyte0,NULL));
	int bufLen=env->GetArrayLength(abyte0);
	
	sgenrand(LEDWORD(buf+8),g_mt,g_mti);
	DWORD r=genrand(g_mt,g_mti);
	int n=r^LEDWORD(buf+4);
	if(n<=bufLen)
	{
		jbyte *tmp=new jbyte[n];
		//if(tmp==NULL)
		//{
		//	env->ReleasePrimitiveArrayCritical(abyte0,buf,0);
		//	return NULL;
		//}

		for (int i = 0; i < n; ++i )
		{
			int t = 8 * i % -4;
			if ( !t )
				r = genrand(g_mt, g_mti);
			tmp[i] = buf[bufLen - 1 - i] ^ (r >> t);
		}
		
		//env->SetByteArrayRegion(env->NewByteArray(n),0,n,tmp);
		env->ReleasePrimitiveArrayCritical(abyte0,buf,0);
		int sutflen=env->GetStringUTFLength(s);
		int slen=env->GetStringLength(s);
		char *stmp=new char[sutflen+1];
		//if(stmp==NULL)
		//{
		//	delete[] tmp;
		//	return NULL;
		//}

		env->GetStringUTFRegion(s,0,slen,stmp);
		for(int i=0;i<slen;++i)
		{
			if(stmp[i]=='.')
				stmp[i]='/';
		}
		
		jclass ret=env->DefineClass(stmp,pthis,tmp,n);

		delete []stmp;
		delete []tmp;
		return ret;
	}

	return NULL;
}

int g_mtiTool=625;
DWORD g_mtTool[624];

#define BYTE0(x) (BYTE) ((x)%0x000000FF)
#define BYTE1(x) (BYTE)(((x)%0x0000FF00)>> 8)
#define BYTE2(x) (BYTE)(((x)%0x00FF0000)>>16)
#define BYTE3(x) (BYTE)(((x)%0xFF000000)>>24)

JNIEXPORT jbyteArray JNICALL Java_backstage_tool_classcoder_ClassCoder_codeClassNative( JNIEnv *env, jobject, jbyteArray abyte0)
{
	jbyte *buf=reinterpret_cast<jbyte*>(env->GetPrimitiveArrayCritical(abyte0,NULL));
	int bufLen=env->GetArrayLength(abyte0);
	
	sgenrand(2 * time(NULL) + 38146, g_mtTool, g_mtiTool);
	int n=genrand(g_mtTool,g_mtiTool);
	int size=n+bufLen;
	jbyte *tmp=new jbyte[size];
	for(int i=0;i<=n/4;++i)
		(reinterpret_cast<DWORD*>(tmp))[i]=genrand(g_mtTool,g_mtiTool);
	DWORD r=genrand(g_mtTool,g_mtiTool);
	tmp[8]=BYTE3(r);tmp[9]=BYTE2(r);tmp[10]=BYTE1(r);tmp[11]=BYTE0(r);
	sgenrand(r,g_mtTool,g_mtiTool);
	r=genrand(g_mtTool,g_mtiTool);
	tmp[4]=BYTE3(r^bufLen);tmp[5]=BYTE2(r^bufLen);tmp[6]=BYTE1(r^bufLen);tmp[7]=BYTE0(r^bufLen);
	for(int i=0;i<bufLen;++i)
	{
		int t = 8 * i % -4;
		if ( !t )
			r = genrand(g_mtTool, g_mtiTool);
		buf[bufLen - 1 - i] = buf[i] ^ (r >> t);
	}
	jbyteArray ret = env->NewByteArray(size);
	env->SetByteArrayRegion(ret,0,size,tmp);
	delete[] tmp;
	env->ReleasePrimitiveArrayCritical(abyte0,buf,0);
	return ret;
}

